module VirtualCity.World

open Casanova
open Casanova.Utilities
open Casanova.Core
open Casanova.Coroutines
open Casanova.Game
open Casanova.Input
open Casanova.Math
open Casanova.Drawing
open VirtualCity.City
open VirtualCity.Rendering
open Casanova.StandardLibrary.Core
open Casanova.StandardLibrary.Physics


/// The world contains:
/// - the layers used for rendering
/// - the definition of the virtual city
/// - the camera that can move/zoom around the city
/// - the set of tiles that make up the game background
type [<CasanovaEntity>] World = {
  Layers     : Layers
  City       : City
  Camera     : Camera2D
  Tiles      : List<DrawableSprite>
  Dashboard  : Dashboard
}


/// The dashboard contains a simple background texture that
/// acts as the background for general information about the 
/// game: clock, selected agent, etc.
and [<CasanovaEntity>] Dashboard = {
  SelectedAgent : Rule<Option<Ref<Agent>>>
  Box           : DrawableSprite
  ClockText     : DrawableText
  AgentText     : DrawableText
  Selection     : DrawableSprite
  Home          : DrawableSprite
  Work          : DrawableSprite
  AutoSelect    : bool
  FPSCounter    : FPSCounter
} with
  static member SelectedAgentRule(world:World,self:Dashboard,dt:float32<s>) =
    if self.AutoSelect then
      try
        Some(ref(!world.City.Agents |> Seq.filter (fun a -> (!a.Stats).VitalMin > 0.0f) |> Seq.minBy (fun a -> (!a.Stats).VitalMin)))
      with
      | _ -> !self.SelectedAgent
    else
      !self.SelectedAgent
  static member ClockTextStringRule(world:World,self:Dashboard,dt:float32<s>) =
    let time = !world.City.Clock.Time
    sprintf "%02d/%02d\n%02d:%02d\n%dx" time.Day time.Month time.Hour time.Minute ((time_speed |> int) / 60)
  static member AgentTextStringRule(world:World,self:Dashboard,dt:float32<s>) =
    match !self.SelectedAgent with
    | None -> ""
    | Some agent ->
      let agent = !agent
      
      let mutable amountofgroceries = 0

      for i = 0 to agent.Inventory.Length-1 do
        if (System.String.Equals(agent.Inventory.Item(i).Name, "Groceries", System.StringComparison.CurrentCultureIgnoreCase)) then
          amountofgroceries <- amountofgroceries + 1     
      
      sprintf "%s\n%s\n%4.2f$\nGroceries:%i\n%s\n" agent.Name ((!agent.Stats).ToString2()) (!agent.Money |> float32) (amountofgroceries) (!agent.CurrentAction)
  static member SelectionScaleRule(world:World,self:Dashboard,dt:float32<s>) =
    match !self.SelectedAgent with
    | None -> Vector2.Zero
    | Some _ -> Vector2.One
  static member SelectionPositionRule(world:World,self:Dashboard,dt:float32<s>) =
    match !self.SelectedAgent with
    | None -> Vector2.Zero
    | Some agent ->
      let agent = !agent
      (!agent.Physical.Position + agent.VisualOffset)
  static member WorkScaleRule(world:World,self:Dashboard,dt:float32<s>) =
    match !self.SelectedAgent with
    | None -> Vector2.Zero
    | Some a -> Vector2.One
  static member WorkPositionRule(world:World,self:Dashboard,dt:float32<s>) =
    match !self.SelectedAgent with
    | None -> Vector2.Zero
    | Some agent ->
      let agent = !agent
      (!agent.Work).Base.Position + agent.VisualOffset
  static member HomeScaleRule(world:World,self:Dashboard,dt:float32<s>) =
    match !self.SelectedAgent with
    | None -> Vector2.Zero
    | Some a -> Vector2.One
  static member HomePositionRule(world:World,self:Dashboard,dt:float32<s>) =
    match !self.SelectedAgent with
    | None -> Vector2.Zero
    | Some agent ->
      let agent = !agent
      (!agent.Home).Base.Position + agent.VisualOffset
